using CriWare;
using UnityEngine;

namespace IQIGame.Onigao.Game
{
    /// <summary>
    /// Criware的AtomSource扩展，给带音源的物体使用,供场景配置，无需代码控制，自动播放。例如：场景中的风声，水生。
    /// 如果是代码控制的3d发声，请使用CriAtomSource，请不要使用该脚本。例如：角色发出的3d声音
    /// </summary>
    public class GameAutoAudioSource : CriAtomSource
    {
        #region Variables
        [SerializeField]
        private AudioSourceType _sourceType = AudioSourceType.LoopSource;
        [SerializeField]
        private bool _removeSheetOnDestroy;

        public enum AudioSourceAdapterType
        {
            Sound3D = 0,
            AreaSphere = 1,
            AreaCube = 2,
        }

        [SerializeField]
        [Header("播放声音的适配类型")]
        private AudioSourceAdapterType _adapterType = AudioSourceAdapterType.Sound3D;

        [SerializeField]
        [Header("播放声音的范围(3d表示播放范围，2d表示衰减范围)")]
        private float _playAudioDistance = 15;

        [SerializeField]
        [Header("停止声音的额外范围，是在播放的范围上相加的值")]
        // 停止范围比播放大，主要防止频繁的播放停止声音
        private float _stopAudioExtraDistance = 3;

        [SerializeField]
        [Header("AISAC距离控制声音的名字")]
        private string _AISACDistanceName = "EnvDistanceVol";

        [SerializeField]
        [Header("球型区域范围(半径)")]
        private float _sphereRadius = 3;

        [SerializeField]
        [Header("立方体区域范围(半个xyz)")]
        private Vector3 _cuebeHalfSize = Vector3.one;

        /// <summary>
        /// 当前是否在播放中
        /// </summary>
        private bool _isPlaying = false;
        #endregion

        #region Properties
        public AudioSourceType sourceType
        {
            get { return this._sourceType; }
            set { this._sourceType = value; }
        }

        public AudioSourceAdapterType adapterType
        {
            get { return this._adapterType; }
            set { this._adapterType = value; }
        }

        public float playAudioDistance
        {
            get { return this._playAudioDistance; }
            set { this._playAudioDistance = value; }
        }

        public float stopAudioExtraDistance
        {
            get { return this._stopAudioExtraDistance; }
            set { this._stopAudioExtraDistance = value; }
        }

        public float sphereRadius
        {
            get { return this._sphereRadius; }
            set { this._sphereRadius = value; }
        }

        public Vector3 cuebeHalfSize
        {
            get { return this._cuebeHalfSize; }
            set { this._cuebeHalfSize = value; }
        }

        public bool removeSheetOnDestroy
        {
            get { return this._removeSheetOnDestroy; }
            set { this._removeSheetOnDestroy = value; }
        }

        public string AISACDistanceName
        {
            get { return this._AISACDistanceName; }
            set { this._AISACDistanceName = value; }
        }
        #endregion

        #region OnDrawGizmos

#if UNITY_EDITOR

        static private readonly Color c_CriWareLightBlue = new Color(0.332f, 0.661f, 0.991f);
        private Quaternion currentGizmoRotation = Quaternion.identity;
        private Quaternion lastGizmoRotation = Quaternion.identity;

        public new void OnDrawGizmos()
        {
            if (this.enabled == false) { return; }
            var gizmoColor = (!Application.isPlaying || this.status == Status.Playing) ? c_CriWareLightBlue : Color.gray;
            if (this.freezeOrientation == false)
            {
                currentGizmoRotation = transform.rotation;
                lastGizmoRotation = currentGizmoRotation;
            }
            else if (Application.isPlaying)
            {
                currentGizmoRotation = lastGizmoRotation;
            }
            else
            {
                currentGizmoRotation = Quaternion.identity;
            }
            Gizmos.matrix = Matrix4x4.identity;
            UnityEditor.Handles.color = gizmoColor;
            UnityEditor.Handles.DrawLine(this.transform.position, this.transform.position + this.currentGizmoRotation * Vector3.forward);
            UnityEditor.Handles.DrawLine(this.transform.position, this.transform.position + this.currentGizmoRotation * Vector3.up);
            UnityEditor.Handles.ArrowHandleCap(1, this.transform.position + this.currentGizmoRotation * Vector3.forward, this.currentGizmoRotation, 1f, EventType.Repaint);
            UnityEditor.Handles.CircleHandleCap(1, this.transform.position, this.currentGizmoRotation * Quaternion.LookRotation(Vector3.up), 1f, EventType.Repaint);

            switch (this.adapterType)
            {
                case AudioSourceAdapterType.AreaSphere:
                    Gizmos.matrix = Matrix4x4.TRS(this.transform.position, this.transform.rotation, Vector3.one);
                    Gizmos.color = Color.blue;
                    Gizmos.DrawWireSphere(Vector3.zero, this.sphereRadius);
                    break;
                case AudioSourceAdapterType.AreaCube:
                    Gizmos.matrix = Matrix4x4.TRS(this.transform.position, this.transform.rotation, Vector3.one);
                    Gizmos.color = Color.blue;
                    Gizmos.DrawWireCube(Vector3.zero, this.cuebeHalfSize * 2);
                    break;
            }
        }

#endif
        #endregion

        #region Functions


        protected override void OnDisable()
        {
            base.OnDisable();

            StopAudio();
            if (this._removeSheetOnDestroy && !string.IsNullOrEmpty(this.cueSheet))
            {
                ManagerCenter.Audio.RemoveCueSheet(this.cueSheet);
            }
        }

        /**
         * <summary>Starts playing the Cue that is set.</summary>
         * <remarks>
         * <para header='Description'>You must set the CriAtomSource::playOnStart, CriAtomSource::CueName
         * properties in advance.</para>
         * </remarks>
         */
        protected override void PlayOnStart()
        {
            //if (this.playOnStart && !String.IsNullOrEmpty(this.cueName))
            //{
            //    ManagerCenter.Audio.GetOrAddCueSheet(this.cueSheet, this.sourceType);
            //    this.Play();
            //}
        }

        protected virtual void PlayAudio()
        {
            if (_isPlaying)
            {
                return;
            }
            if (!string.IsNullOrEmpty(this.cueName) && !string.IsNullOrEmpty(this.cueSheet))
            {
                ManagerCenter.Audio.GetOrAddCueSheet(this.cueSheet, this.sourceType);
                this.Play();
                _isPlaying = true;
            }
        }

        protected virtual void StopAudio()
        {
            if (_isPlaying)
            {
                _isPlaying = false;
                this.Stop();
            }
        }

        /// <summary>
        /// 刷新距离的AISAC控制器的值，由音频资源提供。
        /// </summary>
        /// <param name="value"></param>
        protected virtual void RefreshAISACDistanceValue(float value)
        {
            this.SetAisacControl(_AISACDistanceName, value);
        }


        protected override void UpdatePosition()
        {
            base.UpdatePosition();

            if (GameAudioListener.Instance == null)
            {
                StopAudio();
                return;
            }

            var selfPosition = this.transform.position;
            var listenerPosition = GameAudioListener.Instance.transform.position;

            switch (_adapterType)
            {
                case AudioSourceAdapterType.Sound3D:
                    {
                        // 普通的3d声音
                        var distance = Vector3.Distance(selfPosition, listenerPosition);
                        if (_isPlaying)
                        {
                            if (distance > (_playAudioDistance + _stopAudioExtraDistance))
                            {
                                StopAudio();
                            }
                            return;
                        }

                        if (distance <= _playAudioDistance)
                        {
                            this.PlayAudio();
                        }
                    }
                    break;
                case AudioSourceAdapterType.AreaSphere:
                    {
                        // 球型区域s
                        var distance = Vector3.Distance(selfPosition, listenerPosition);
                        if (_isPlaying)
                        {

                            if (distance > (_playAudioDistance + _stopAudioExtraDistance + _sphereRadius))
                            {
                                StopAudio();
                            }
                            float ratioValue1 = Mathf.Min(1, Mathf.Max(distance - _sphereRadius, 0) / _playAudioDistance);
                            RefreshAISACDistanceValue(ratioValue1);
                            return;
                        }

                        float ratioValue2 = Mathf.Max(distance - _sphereRadius, 0) / _playAudioDistance;

                        if (ratioValue2 <= 1)
                        {
                            this.PlayAudio();

                            RefreshAISACDistanceValue(ratioValue2);
                        }
                    }
                    break;
                case AudioSourceAdapterType.AreaCube:
                    {
                        //立方体区域

                        // 点到立方体表面的距离
                        var toSurfacedistance = DistancePointToRectangle3D(listenerPosition, selfPosition, _cuebeHalfSize, this.transform.rotation);
                        if (_isPlaying)
                        {
                            if (toSurfacedistance > (_playAudioDistance + _stopAudioExtraDistance))
                            {
                                StopAudio();
                            }
                            float ratioValue1 = Mathf.Min(1, toSurfacedistance / _playAudioDistance);
                            RefreshAISACDistanceValue(ratioValue1);
                            return;
                        }

                        float ratioValue2 = toSurfacedistance / _playAudioDistance;
                        if (ratioValue2 <= 1)
                        {
                            this.PlayAudio();
                            RefreshAISACDistanceValue(ratioValue2);
                        }
                    }
                    break;
            }
        }

        /// <summary>
        /// 点到立方体表面的距离
        /// </summary>
        /// <param name="point"></param>
        /// <param name="cubeCenter"></param>
        /// <param name="halfSize"></param>
        /// <param name="rectangleRotation"></param>
        /// <returns></returns>
        private static float DistancePointToRectangle3D(Vector3 point, Vector3 cubeCenter, Vector3 halfSize, Quaternion rectangleRotation)
        {
            // 将点转换到矩形的局部空间
            Vector3 localPoint = Quaternion.Inverse(rectangleRotation) * (point - cubeCenter);

            // 计算局部空间中点与矩形中心的相对位置
            Vector3 relativePoint = localPoint;

            // 获取相对位置的绝对值，并减去矩形大小的一半
            Vector3 outside = new Vector3(
                Mathf.Max(Mathf.Abs(relativePoint.x) - halfSize.x, 0),
                Mathf.Max(Mathf.Abs(relativePoint.y) - halfSize.y, 0),
                Mathf.Max(Mathf.Abs(relativePoint.z) - halfSize.z, 0)
            );

            // 点到矩形边缘的最短距离是outside向量的长度
            return outside.magnitude;
        }

        #endregion
    }
}
